const { Controller, Joi } = require('dx-router-admin');
const uniCaptcha = require('uni-captcha');
const createConfig = require('uni-config-center');
const loginCore = require('../loginCore/index.js');

module.exports = class Index extends Controller {
	constructor(ctx) {
		super(ctx);
	}
	//获取验证码
	async getCaptcha() {
		const { $dx } = this;
		let scene = $dx.request.post('scene');
		let deviceId = $dx.request.deviceId;
		if (!deviceId) {
			return $dx.fail($dx.$t('parameter error', 'deviceId '));
		}
		if (!scene) {
			return $dx.fail($dx.$t('parameter error', 'scene '));
		}
		const { errMsg, code, captchaBase64 } = await uniCaptcha.create({
			deviceId,
			scene,
			width: 100,
			height: 45,
			background: '#64aaff',
			mode:'bmp'
		});
		if (code !== 0) {
			return $dx.fail(errMsg);
		}
		return $dx.success($dx.$t('operation succeeded'), captchaBase64);
	}
	//登录
	async login() {
		let { $dx } = this;
		let loginType = $dx.request.post('loginType');
		let loginObject = loginCore.get(loginType);
		if (!loginObject) {
			return $dx.fail($dx.$t('login mode error', loginType ? `:(${loginType})` : ''));
		}
		let result = await loginObject.login.call(this);
		return $dx.success($dx.$t('operation succeeded'), result);
	}
	//注册
	async register(data) {
		let schema = Joi.object({
			username: Joi.string().required().error(new Error('用户名校验未通过')),
			password: Joi.string().required().error(new Error('密码校验未通过')),
			captcha: Joi.string().required().error(new Error('验证码校验未通过')),
		});
		const { error } = schema.validate(data, {
			abortEarly: true,
			allowUnknown: true,
		});
		if (error) {
			return this.$dx.fail(error.message);
		}
		let deviceId = this.$dx.request.deviceId;
		let { username, password, captcha, invite_code } = data;
		const now = Date.now();
		// 同一设备，查询是否在 {2小时} 内 {大于3条} 有 {注册} 数据，注册频繁限制
		const recordDate = 120 * 60 * 1000;
		let total = await this.$dx.service.logs
			.where('device_id', deviceId)
			.where('create_date', '>', now - recordDate)
			.where('type', 'register')
			.count();
		if (total > 3) {
			return this.$dx.fail('操作频繁，请稍后再试～');
		}
		let user = await this.$dx.service.user.where('username', username).find();
		if (user && user._id) {
			return this.$dx.fail('账号已经存在');
		}
		const verifyRes = await uniCaptcha.verify({
			captcha,
			device_uuid: deviceId,
			scene: 'register',
		});
		// 验证失败
		if (verifyRes.code !== 0) {
			return this.$dx.fail(verifyRes.errMsg);
		}
		let { passwordHash, version } = this.$dx.service.user.getPasswordExtMethod(password);
		// dcloud_appid
		let dcloud_appid = [];
		if (this.$dx.request.appId) {
			dcloud_appid.push(this.$dx.request.appId);
		}
		// 邀请码，上级邀请信息
		let invite_time = 0,
			inviter_uid = [];
		if (invite_code) {
			invite_time = now;
			let perentUser = await this.$dx.service.user.where('my_invite_code', invite_code).field('inviter_uid').find();
			if (perentUser) {
				inviter_uid = perentUser.inviter_uid;
				inviter_uid.unshift(perentUser._id);
			}
		}
		// 新用户
		const uid = await this.$dx.service.user.insert({
			nickname: username,
			username,
			password: passwordHash,
			password_secret_version: version,
			register_date: now,
			register_ip: this.$dx.request.ip,
			dcloud_appid,
			my_invite_code: '',
			invite_time,
			inviter_uid,
		});
		// 生成邀请码
		await this.$dx.service.user.save({
			_id: uid,
			my_invite_code: this.$dx.utils.generateInviteCode(uid),
		});
		//日志
		await this.$dx.service.logs.addLoginLog(uid, username, 'register', !uid ? 0 : 1);
		if (!uid) {
			return this.$dx.fail('注册失败');
		}
		return this.$dx.success('注册成功');
	}
	//发送验证码
	async sendSmsCode({ mobile, scene }) {
		const { $dx } = this;
		if (!$dx.utils.isMobile(mobile)) {
			return $dx.fail('手机号码格式错误');
		}
		if (!['login', 'register', 'bind', 'unbind', 'forget'].includes(scene)) {
			return $dx.fail('验证码类型不正确');
		}
		const uniIdConfig = createConfig({
			pluginId: 'uni-id', // 插件id
			// defaultConfig: {},
			customMerge: function (defaultConfig, userConfig) {
				return Object.assign(defaultConfig, userConfig);
			},
		});
		// 生成验证码可以按自己的需求来，这里以生成6位数字为例
		const randomStr = '00000' + Math.floor(Math.random() * 1000000);
		const code = randomStr.substring(randomStr.length - 6);
		const config = uniIdConfig.config('service.sms');
		const status = await loginCore.get('sms').sendCode.call(this, config, mobile, code);
		if (status) {
			const now = Date.now();
			let record = {
				device_uuid: $dx.request.deviceId,
				mobile,
				scene,
				code,
				state: 0,
				ip: $dx.request.ip,
				created_date: now,
				expired_date: now + config.codeExpiresIn * 1000,
			};
			await $dx.service.verifyCodes.insert(record);
			return $dx.success($dx.$t('operation succeeded'));
		}
		return $dx.fail($dx.$t('operation failed'));
	}
	//手机号码找回密码
	async forget(data) {
		let schema = Joi.object({
			mobile: Joi.string().required().error(new Error('手机号码必须填写')),
			password: Joi.string().required().error(new Error('密码必须填写')),
			code: Joi.string().required().error(new Error('验证码必须填写')),
		});
		const { error } = schema.validate(data, {
			abortEarly: true,
			allowUnknown: true,
		});
		if (error) {
			return this.$dx.fail(error.message);
		}
		let { mobile, password, code } = data;
		if (!this.$dx.utils.isMobile(mobile)) {
			return this.$dx.fail('手机号码格式错误');
		}
		const user = await this.$dx.service.user.where('mobile', mobile).find();
		if (!user) {
			return this.$dx.fail('用户不存在');
		}
		// 校验验证码
		await this.$dx.service.verifyCodes.checkVerifyCode(mobile, code, 'forget');
		// 更新密码
		let { passwordHash, version } = this.$dx.service.user.getPasswordExtMethod(password);
		await this.$dx.service.user.save({
			_id: user._id,
			password: passwordHash,
			password_secret_version: version,
		});
		//日志
		await this.$dx.service.logs.addLoginLog(user._id, user.username, 'forget', 1);
		return this.$dx.success('密码修改成功');
	}
};
